import * as THREE from 'three';
import Event from './Event';
import GreenHouse from './GreenHouse/GreenHouse';
import Field from './Field/Field';
import { createCameraTween } from './tools/useTween';
import { useBloom } from './tools/useBloom';
interface SpaceAssemblerEvents {
  [SpaceAssembler.EVENT_BUILDING_UPDATE]: (params: { greenhouses?: Editor.GreenHouse[]; fields?: Editor.Field[] }) => void;
}

/** 用于在Space中渲染大棚 */
export interface Space_GreenHouseRenderData extends Editor.GreenHouseRenderData {
  /** 基准点 默认(0,0,0) */
  basePoint?: THREE.Vector3;
}

/** 用于在Space中渲染田块 */
export interface Space_FieldRenderData extends Editor.FieldRenderData {
  /** 基准点 默认(0,0,0) */
  basePoint?: THREE.Vector3;
}

interface SpaceAssemblerOption {
  scene: THREE.Scene;
  camera: THREE.PerspectiveCamera;
  renderer: THREE.WebGLRenderer;
  controls: Editor.Controls;
  /** FIXME: 编辑器box-id 用于bloom*/
  boxId: string;
  /** 预加载大棚 */
  preloadGreenHouses?: Array<Space_GreenHouseRenderData>;
  /** 预加载田块 */
  preloadFields?: Array<Space_FieldRenderData>;
}

export default class SpaceAssembler extends Event<SpaceAssemblerEvents> {
  /** 大棚or田块 更新 */
  static EVENT_BUILDING_UPDATE = 'BUILDING_UPDATE';

  greenhousesMap: Map<number | string, Editor.GreenHouse> = new Map();

  fieldsMap: Map<number | string, Editor.Field> = new Map();

  scene: THREE.Scene;
  camera: THREE.PerspectiveCamera;
  controls: Editor.Controls;
  composer: ReturnType<typeof useBloom>['composer'];
  outlinePass: ReturnType<typeof useBloom>['outlinePass'];

  /** 正在编辑的building */
  private _editingBuilding: Editor.Building | null = null;

  constructor(option: SpaceAssemblerOption) {
    super();
    const { scene, controls, camera } = option;
    this.scene = scene;
    this.camera = camera;
    this.controls = controls;
    this._init(option);
  }

  private _init(option: SpaceAssemblerOption) {
    const { preloadGreenHouses, preloadFields, scene, camera, renderer, boxId } = option;
    // 预渲染大棚
    if (Array.isArray(preloadGreenHouses)) {
      preloadGreenHouses.forEach((renderData) => {
        this.addGreenHouse(renderData);
      });
    }
    // 预渲染田块
    if (Array.isArray(preloadFields)) {
      preloadFields.forEach((renderData) => {
        this.addField(renderData);
      });
    }
    // 启用轮廓bloom
    const { composer, outlinePass } = useBloom({
      scene,
      camera,
      renderer,
      boxId,
    });
    this.composer = composer;
    this.outlinePass = outlinePass;
  }

  /** 向当前space中添加一个新大棚
   * - 该操作建立起space和某个大棚的映射关系
   */
  addGreenHouse(renderData: Space_GreenHouseRenderData) {
    const { id, basePoint = new THREE.Vector3(0, 0, 0), preloadCropPlotRawDatas = [], preloadDeviceRawDatas = [], ..._resRenderData } = renderData;

    if (this.greenhousesMap.has(id)) return;
    const greenhouse = new GreenHouse({
      ..._resRenderData,
      // MARK:必须显式加入controls
      controls: this.controls,
      id,
      scene: this.scene,
      plugins: [
        {
          name: 'PlantAreaManager',
          option: {
            camera: this.camera,
            preloadCropPlotRawDatas,
          },
        },
        {
          name: 'DeviceManager',
          option: {
            camera: this.camera,
            preloadDeviceRawDatas,
          },
        },
      ],
    });
    greenhouse.on(GreenHouse.EVENT_BASEMODEL_LOADED, (model: THREE.Object3D | null) => {
      if (model) {
        // 修正模型位置
        model.position.copy(basePoint);
        // 添加到场景
        this.greenhousesMap.set(id, greenhouse);
        this._emitEvent(SpaceAssembler.EVENT_BUILDING_UPDATE, {
          greenhouses: Array.from(this.greenhousesMap.values()),
        });
      } else {
        console.error('[SpaceAssembler]-模型加载失败');
      }
    });
  }

  /** 根据id 删除大棚
   *  - 该操作解除space和某个大棚的映射关系
   */
  removeGreenHouseById(id: number | string) {
    // 取出greenhouse
    const greenhouse = this.greenhousesMap.get(id);
    if (!greenhouse) return;

    // 如果移除的是正在编辑的大棚，应该先安全取消编辑态
    const { transformControls } = this.controls;
    const controlObject = transformControls.object;
    if (controlObject && controlObject.uuid === greenhouse.model.uuid) {
      this.closeEdit();
    }
    // 删除操作
    greenhouse.destroy();
    this.greenhousesMap.delete(id);
    this._emitEvent(SpaceAssembler.EVENT_BUILDING_UPDATE, {
      greenhouses: Array.from(this.greenhousesMap.values()),
    });
  }

  /** 向当前space中添加一个新田块
   * - 该操作建立起space和某个田块的映射关系
   **/
  addField(renderData: Space_FieldRenderData) {
    const { id, basePoint = new THREE.Vector3(0, 0, 0) } = renderData;
    if (this.fieldsMap.has(id)) return;
    const field = new Field({
      ...renderData,
      scene: this.scene,
      plugins: [],
    });
    field.on(Field.EVENT_BASEMODEL_LOADED, (model: THREE.Object3D | null) => {
      if (model) {
        model.position.copy(basePoint);
        this.fieldsMap.set(id, field);
        this._emitEvent(SpaceAssembler.EVENT_BUILDING_UPDATE, {
          fields: Array.from(this.fieldsMap.values()),
        });
      }
    });
  }

  /**
   * 根据id 删除田块
   *  - 该操作解除space和某个田块的映射关系
   */
  removeFieldById(id: number | string) {
    const field = this.fieldsMap.get(id);
    if (!field) return;

    // 如果移除的是正在编辑的田块，应该先安全取消编辑态
    const { transformControls } = this.controls;
    const controlObject = transformControls.object;
    if (controlObject && controlObject.uuid === field.model.uuid) {
      this.closeEdit();
    }

    // 删除操作
    field.destroy();
    this.fieldsMap.delete(id);
    this._emitEvent(SpaceAssembler.EVENT_BUILDING_UPDATE, {
      fields: Array.from(this.fieldsMap.values()),
    });
  }

  /** 开启编辑模式
   *
   * flow:
   *  - ✅明确要attach的object + attach
   * FIXME: 考虑是否允许 使用enableTransformModeMenu
   *  - 快速俯视图切换
   *  - ⭕开启快速键盘控制
   */
  openEdit(building: Editor.Building) {
    if (this._editingBuilding) this.closeEdit();
    const { transformControls, orbitControls } = this.controls;
    const { basePoint } = building.getInfo();
    createCameraTween({
      camera: this.camera,
      controls: orbitControls,
      endPos: basePoint.clone().addScalar(500),
      endTarget: basePoint.clone(),
      duration: 500,
    });

    // 开启跟随变换
    const deviceManager = building.getPluginByName('DeviceManager');
    deviceManager && deviceManager.enablefollowTransform();
    const plantAreaManager = building.getPluginByName('PlantAreaManager');
    plantAreaManager && plantAreaManager.enablefollowTransform();

    // 开启transformcontrol菜单
    this.controls.enableTransformModeMenu({
      initialMode: 'translate',
      visibleModes: [
        {
          mode: 'translate',
          callback: () => {
            transformControls.showX = true;
            transformControls.showY = false;
            transformControls.showZ = true;
          },
        },
        {
          mode: 'rotate',
          callback: () => {
            transformControls.rotationSnap = Math.PI / 4;
            transformControls.showX = false;
            transformControls.showY = true;
            transformControls.showZ = false;
          },
        },
      ],
    });
    transformControls.attach(building.model);

    this.outlinePass.selectedObjects = [building.model];
    this._editingBuilding = building;
  }

  closeEdit() {
    if (!this._editingBuilding) return;
    // 关闭跟随变换
    const deviceManager = this._editingBuilding.getPluginByName('DeviceManager');
    deviceManager && deviceManager.disablefollowTransform();
    const plantAreaManager = this._editingBuilding.getPluginByName('PlantAreaManager');
    plantAreaManager && plantAreaManager.disablefollowTransform();

    // 销毁enableTransformModeMenu
    this.controls.detachTransfromControls();
    this.outlinePass.selectedObjects = [];
    this._editingBuilding = null;
  }

  /** 在requestAnimation中调用 */
  update() {
    this.composer.render();
  }

  destroy() {
    this.composer && this.composer.dispose();
    this.composer = null;
    this.outlinePass = null;
  }
}
